# ***** BEGIN LICENSE BLOCK *****
#   Copyright (c) 2006-2007 Slide Inc
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   The Initial Developer of the Original Code is
#   Adam Christian.
#   Portions created by the Initial Developer are Copyright (C) 2008
#   the Initial Developer. All Rights Reserved.
#
#   Contributor(s):
#   Adam Christian <adam.christian@gmail.com>
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
# ***** END LICENSE BLOCK *****

import SocketServer
from subprocess import Popen, PIPE, call
import threading, time, sys, copy, smtplib, os

#setup param defaults
params = {}
params['root'] = '.'
params['test'] = 'googclickthrough.py'
params['browsers'] = ['firefox', 'safari', 'ie']
params['url'] = 'http://www.google.com'
params['continuous'] = False
params['port'] = 5555;

#build params from cmd line args
for arg in sys.argv:
    if arg.find('-help') is not -1:
        print '''WindmillD Help:\n
    root (required): The root directory to look for files to run.
    browsers (defaults to firefox, safari, ie): Comma delimited list of browsers this instance supports.
    url: (defaults to http://www.google.com) The default url (if users forget to provide it) that the tests run against.
    test: A default test to run if users forget to provide one, will default to the full test run.
    continuous: If the string continuous is provided as an argument it will be turned on.
    port: The port you want the server to run on assuming you want to change it from the default, 5555.\n
    Example: python windmilld.py root=~/Desktop/tests browsers=firefox,safari url=http://www.google.com continuous'''
        exit()
    if arg.find('root') is not -1:
        val = arg.split('=')[1]
        vlen = len(val) - 1
        #needs to end with a /, so being smart about it
        if val[vlen] is not '/':
            val = val + '/'
        print "Setting root to " + val
        params['root'] = val
    if arg.find('browsers') is not -1:
        print "Setting browsers to " + str(arg.split('=')[1])
        params['browsers'] = arg.split('=')[1].split[',']
    if arg.find('url') is not -1 and arg.find('http://') is not -1:
        print "Setting url to " + arg.split('=')[1]
        params['url'] = arg.split('=')[1]
    if arg.find('test') is not -1:
        print "Setting default test to " + arg.split('=')[1]
        params['test'] = arg.split('=')[1]
    if arg.find('continuous') is not -1:
        params['continuous'] = True
    if arg.find('port') is not -1:
        params['port'] = arg.split('=')[1]
        
#keep track of the windmill test runs that have been queued up
rQueue = []
results = []
clients = []

def fileExists(f):
    try:
        file = open(f)
    except IOError:
        return False
    return True

def sendClient(client_str, text):
    for client in clients:
           if str(client.client_address) == client_str:
               client.request.send(text)

def safari_delete_temp():
    print 'Removing Safari Temporary Files.\n\r'
    os.system('rm '+ os.path.normpath(os.path.expanduser('~/'))+'/Library/Cookies/Cookies.plist')

def win_delete_temp():
    print 'Removing Internet Explorer Temporary Files.\n\r'
    call('clear_temp.bat')
    #for directory in ['/Documents/Temp', '/Docs/otherTemp']:
    #os.system(cmd)
    #os.system('RunDll32.exe InetCpl.cpl,ClearMyTracksByProcess 255')
    # os.system('FOR /D %%G IN (\"C:\\Documents and Settings\\*.*\") DO DEL/S/Q/F \"%%G\\Cookies\\*.*\\"')
    # os.system('FOR /D %%G IN (\"C:\\Documents and Settings\\*.*\") DO DEL/S/Q/F \"%%G\\Local Settings\\Temp\\*.*\"')
    # os.system('FOR /D %%G IN (\"C:\\Documents and Settings\\*.*\") DO DEL/S/Q/F \"%%G\\Local Settings\\History\\*.*\"')
    # os.system('FOR /D %%G IN ("C:\\Documents and Settings\\*.*\") DO DEL/S/Q/F \"%%G\\Local Settings\\Temporary Internet Files\\*.*\"')
   
   #os.system('rd /S /Q \"C:\\Documents and Settings\\%username%\\Local Settings\\Temporary Internet Files\\\"')
   # os.system('Del /Q \"%Userprofile%\\Local Settings\\History\\*.*\"')
   # os.system('Del /Q \"%Userprofile%\\Local Settings\\Temp\\*.*\"')
   # os.system('Del /Q \"%Userprofile%\\Recent\\*.*\"')
   #  os.system('Del /Q \"%Userprofile%\Cookies\*.*\"')
 
#define the socket handler code
class EchoRequestHandler(SocketServer.BaseRequestHandler ):
    
    def setup(self):
        print self.client_address, 'connected!'
        self.request.send('\nWelcome to WindmillD 0.1, ' + str(self.client_address) + '\n\r>')
        if self not in clients: 
            clients.append(self)
    
    def getData(self):                                              
            data = ''
            c = self.request.recv(1024)
            if len(c) <= 1:
                while c != '\r\n':
                    data += c
                    c = self.request.recv(1024)
                    #self.request.send('\b')  # Hide what user is typing -
                    if c == '\r\n':                     #deleting that line is OK
                        break
            else:
                data = c

            if '\r\n' in data:
                data = data.strip('\r\n')

            return data
    
    def handle(self):

        while 1:
            #data = self.request.recv(1024)
            data = self.getData()
            if data.strip() == 'help' or data.strip() == '?':
                help = '''
Commands:
    me: Shows you what the server knows about who you are.
    queue: Shows the jobs in the test queue.
    exit: Kills your connection to the server.
    
A test command can have 3 parameters, name=value pairs:
    browser: A comma delimited list of browsers to run.
    url: The URL where the test starts.
    test: The test you want to run relative to the root the server is running.
    
    Example: browser=firefox,safari url=http://www.google.com test=testgoogle.py'''
                self.request.send(help)
            if data.strip() == 'me':
                self.request.send(str(self.client_address)+"\n\r")
            if data.strip() == 'exit':
                return
            if data.strip() == 'queue':
                self.request.send(str(rQueue)+'\n\r>')
            #if data.strip() == 'firefox' or data.strip() == 'safari':
            else:
                r_params = data.strip().split(' ')
                p_dict = {}
                for e in r_params:
                    e_arr = e.split('=')
                    if len(e_arr) is 2:
                        p_dict[e_arr[0]] = e_arr[1]
                    
                if len(p_dict) is not 0:
                    p_dict['client_address'] = str(self.client_address)
                    
                    try:
                        if p_dict.has_key('url'):
                            if p_dict['url'].find('http://') == -1 or p_dict['url'] == '':
                                raise Exception, "Bad params"
                                
                        #if browser was a comma delmited list, add multiple jobs to run them all
                        if p_dict['browser'].find(',') is not -1:
                            p_dict['browser'] = p_dict['browser'].replace(' ', '')
                            brs = p_dict['browser'].split(',')
                            for b in brs:
                                if b in params['browsers']:
                                    new = copy.copy(p_dict)
                                    new['browser'] = b
                                    rQueue.append(new)
                                    self.request.send('>>Adding '+str(new)+' to the test Queue.\n\r>')
                                else:
                                    raise Exception, "Bad params"
                        else:
                            if p_dict['browser'] not in params['browsers']:
                                raise Exception, "Bad params"
                            rQueue.append(p_dict)
                            self.request.send('>>Adding '+str(p_dict)+' to the test Queue.\n\r>')
                    except:
                        print 'Was given a bad command'
                        self.request.send('>>Invalid parameters.\n\r>')
                        
                else:
                    self.request.send('\n\r>')  
                    
    def finish(self):
        print self.client_address, 'disconnected!'
        self.request.send('>>Bye ' + str(self.client_address) + '\n\r')
        clients.remove(self)

#start a thread to poll
class PollThread ( threading.Thread ):
   def run ( self ):
       while 1:
           #if there is anything in the queue
           if (len(rQueue) != 0):
               #use safe defaults
               t_run = rQueue.pop(0)
               if not t_run.has_key('url') or t_run['url'].find('http://') == -1:
                   t_run['url'] = params['url']
               if not t_run.has_key('browser') or t_run['browser'] not in params['browsers']:
                   t_run['browser'] = 'firefox'
               if not t_run.has_key('test'):
                   t_run['test'] = params['test']
               if not fileExists(params['root']+t_run['test']):
                   sendClient(t_run['client_address'], '>>Test file' + str(t_run['test'])+ ' not found, removing job.\n\r')    
                   return
               
               #if we are in IE, remove all the temp internet files so it doesn't mess up future test runs
               if t_run['browser'] == 'ie':
                   win_delete_temp()
               if t_run['browser'] == 'safari':
                   safari_delete_temp()
                   
               print 'Running test '+ str(t_run)
               #send status to each of the clients connected
               sendClient(t_run['client_address'],'>Starting '+str(t_run)+'...\n\r>')
                   
               proc = Popen(['windmill', t_run['browser'], t_run['url'], 'test='+params['root']+t_run['test'], 'exit'], stdout=PIPE, stderr=PIPE)
               return_code = proc.wait()
               if (proc.stdout.read().find('Error') == -1):
                   sendClient(t_run['client_address'],'>Test '+str(t_run) + ' passed.\n\r>')
                   res = True
               else:
                   sendClient(t_run['client_address'],'>Test '+str(t_run) + ' failed.\n\r>')
                   res = False
                   
               #if the user wants a results email
               # if t_run['email']:
               #     sendEmail(t_run, res)
               #
 
               results.append((t_run, res))
               time.sleep(1)     
                   
           #else:
               #if continuous integration is turned on, run the default set of tests
               #if params['continuous']:
                   #do test run
                   #os.system("svn up "+root)
                   #proc = Popen(['windmill', t_run['browser'], t_run['url'], 'test='+params['root'], 'exit'], stdout=PIPE, stderr=PIPE)
                   # return_code = proc.wait()
                   # if (proc.stdout.read().find('Error') == -1):
                   #     res = True
                   # else:
                   #     res = False
                   #results.append(('root', res))
                   #do something with results, email etc
                   #time.sleep(1)
               
#start a thread to poll
class AppThread ( threading.Thread ):
  def run ( self ):
      server = SocketServer.ThreadingTCPServer(('', params['port']), EchoRequestHandler)
      server.serve_forever()
    
def ipython_shell(locals_dict):
  from IPython.Shell import IPShellEmbed
  ipshell = IPShellEmbed()
  ipshell(local_ns=locals_dict)
  
def code_shell(locals_dict):
  import code
  code.interact(local=locals_dict)

def main():    
    PollThread().start()
    AppThread().start()
    print "Server running..."

    try:
        import IPython
    except:
        IPython = None    
    if IPython is not None and '--usecode' not in sys.argv:
        sys.argv = sys.argv[:1]
        ipython_shell({'queue':rQueue, 'params':params, 'results': results, 'clients': clients})
    else:
        code_shell({'queue':rQueue, 'params':params, 'results': results, 'clients': clients})
    

if __name__ == "__main__": main()

# #admin shell
# while 1:
#     try:
#         shell_in = raw_input( ">")
#         op = exec shell_in
#         print op
#     except:
#         print 'Bad command, try again'